package Classes;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Vector;
import javax.swing.ImageIcon;

/**
 *
 * @author Juampi
 */
public class GoogleMap {

    private static GoogleMap instance = null;
    private static final String URL_UNRESERVED =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
            + "abcdefghijklmnopqrstuvwxyz"
            + "0123456789-_.~";
    private static final char[] HEX = "0123456789ABCDEF".toCharArray();

    private GoogleMap() {
    }

    private double[] geocodeAddress(String address) throws Exception {
        byte[] res = getMap(getGeocodeUrl(address));
        String[] data = split(new String(res), ',');

        if (!data[0].equals("200")) {
            int errorCode = Integer.parseInt(data[0]);
            throw new Exception("Google Maps Exception: " + getGeocodeError(errorCode));
        }

        return new double[]{
                    Double.parseDouble(data[2]), Double.parseDouble(data[3])
                };
    }

    private String getGeocodeUrl(String address) {
        return "http://maps.google.com/maps/geo?q=" + urlEncode(address) + "&output=csv";
    }

    private static String[] split(String s, int chr) {
        Vector res = new Vector();

        int curr;
        int prev = 0;

        while ((curr = s.indexOf(chr, prev)) >= 0) {
            res.addElement(s.substring(prev, curr));
            prev = curr + 1;
        }
        res.addElement(s.substring(prev));

        String[] splitted = new String[res.size()];
        res.copyInto(splitted);

        return splitted;
    }

    private static String getGeocodeError(int errorCode) {
        switch (errorCode) {
            case 400:
                return "Bad request";
            case 500:
                return "Server error";
            case 601:
                return "Missing query";
            case 602:
                return "Unknown address";
            case 603:
                return "Unavailable address";
            case 604:
                return "Unknown directions";
            case 620:
                return "Too many queries";
            default:
                return "Generic error";
        }
    }

    private static String urlEncode(String str) {
        StringBuffer buf = new StringBuffer();
        byte[] bytes = null;
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            DataOutputStream dos = new DataOutputStream(bos);
            dos.writeUTF(str);
            bytes = bos.toByteArray();
        } catch (IOException e) {
            // ignore
        }
        for (int i = 2; i < bytes.length; i++) {
            byte b = bytes[i];
            if (URL_UNRESERVED.indexOf(b) >= 0) {
                buf.append((char) b);
            } else {
                buf.append('%').append(HEX[(b >> 4) & 0x0f]).append(HEX[b & 0x0f]);
            }
        }
        return buf.toString();
    }

    private static byte[] getMap(String url) throws IOException {
        BufferedReader in;
        InputStreamReader isr;
        String inputLine;
        String result = "";
        byte[] bytes;
        try {
            URL google = new URL(url);
            URLConnection con = google.openConnection();
            isr = new InputStreamReader(con.getInputStream());
            in = new BufferedReader(isr);


            while ((inputLine = in.readLine()) != null) {
                result = inputLine;
            }
            in.close();
            bytes = result.getBytes();
            /* InputStream is = con.getInputStream();
            bytes = new byte[con.getContentLength()];
            is.read(bytes);
            is.close();*/

        } catch (Exception ex) {
            System.out.println(ex.getCause());
            System.out.println(ex.getLocalizedMessage());
            bytes = new byte[1];
            return bytes;
        }
        return bytes;
    }

    public static GoogleMap getInstance() {
        if (instance == null) {
            instance = new GoogleMap();
        }
        return instance;
    }

    public ImageIcon getImagenMapa(String addr, int width, int height) throws Exception {
        ImageIcon icImage = null;
        double pos[] = this.geocodeAddress(addr);
        String url = this.getMapUrl(width, height, pos[1], pos[0], 15, "png32");
        try {
            URLConnection con = new URL(url).openConnection();
            InputStream is = con.getInputStream();
            byte bytes[] = new byte[con.getContentLength()];
            ByteArrayOutputStream baos = new ByteArrayOutputStream(con.getContentLength());
            byte data[] = new byte[1024];
            int count = 0;
            int bajando = 0;
            while (bajando < con.getContentLength()) {
                while (((count = (is.read(data, 0, 1024))) > 0)) {
                    baos.write(data, 0, count);
                    bajando += count;
                }
            }
            is.close();
            bytes = baos.toByteArray();
            icImage = new ImageIcon(bytes);
            return icImage;
        } catch (Exception ex) {
            
        }
        return icImage;
    }

    private String getMapUrl(int width, int height, double lng, double lat, int zoom, String format) {
        return "http://maps.google.com/staticmap?center=" + lat + "," + lng + "&format="
                + format + "&zoom=" + zoom + "&size=" + width + "x" + height + "&maptype=roadmap" +
                "&markers=" + lat + "," + lng + "&sensor=false";
    }
}
